home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / Icon 8.1 / msm-1 / icont.sit / tlex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-19  |  20.4 KB  |  801 lines  |  [TEXT/MPS ]

  1. /*
  2.  * tlex.c -- the lexical analyzer.
  3.  */
  4.  
  5. #include "::h:gsupport.h"
  6. #include "tproto.h"
  7. #include "trans.h"
  8. #include "tlex.h"
  9. #include "tree.h"
  10. #include "token.h"
  11. #include <ctype.h>
  12.  
  13. #if MACINTOSH
  14. #if MPW
  15. #include <CursorCtl.h>
  16. #define CURSORINTERVAL 100
  17. #endif                    /* MPW */
  18. #endif                    /* MACINTOSH */
  19.  
  20. /*
  21.  * Prototypes.
  22.  */
  23.  
  24. hidden  int             bufcmp          Params((char *s));
  25. hidden    int        ctlesc        Params((noargs));
  26. hidden    struct toktab   *findres    Params((noargs));
  27. hidden    struct toktab   *getident    Params((int ac,int *cc));
  28. hidden    struct toktab   *getnum        Params((int ac,int *cc));
  29. hidden    struct toktab   *getopr        Params((int ac,int *cc));
  30. hidden    struct toktab   *getstring    Params((int ac,int *cc));
  31. hidden    int        hexesc        Params((noargs));
  32. hidden    int        nextchar    Params((noargs));
  33. hidden    int        octesc        Params((int ac));
  34. hidden    int        setfilenm    Params((int c));
  35. hidden    int        setlineno    Params((noargs));
  36.  
  37. #define isletter(s)    (isupper(c) | islower(c))
  38.  
  39. #if EBCDIC
  40. extern char ToEBCDIC[256], FromEBCDIC[256];
  41. #endif                    /* EBCDIC */
  42.  
  43. #if !EBCDIC
  44. #define tonum(c)        (isdigit(c) ? (c - '0') : ((c & 037) + 9))
  45.  
  46. /*
  47.  * esctab - translates single-character escapes in string literals.
  48.  */
  49.  
  50. static unsigned char esctab[] = {
  51.    000,   001,   002,   003,   004,   005,   006,   007,   /* NUL-BEL */
  52.    010,   011,   012,   013,   014,   015,   016,   017,   /* BS -SI */
  53.    020,   021,   022,   023,   024,   025,   026,   027,   /* DLE-ETB */
  54.    030,   031,   032,   033,   034,   035,   036,   037,   /* CAN-US */
  55.    ' ',   '!',   '"',   '#',   '$',   '%',   '&',   '\'',  /* !"#$%&' */
  56.    '(',   ')',   '*',   '+',   ',',   '-',   '.',   '/',   /* ()*+,-./ */
  57.    000,   001,   002,   003,   004,   005,   006,   007,   /* 01234567 */
  58.    010,   011,   ':',   ';',   '<',   '=',   '>',   '?',   /* 89:;<=>? */
  59.    '@',   'A',   '\b',  'C',   0177,  033,   014,   'G',   /* @ABCDEFG */
  60.    'H',   'I',   'J',   'K',   '\n',  'M',  '\n',   'O',   /* HIJKLMNO */
  61.    'P',   'Q',   '\r',  'S',   '\t',  'U',   013,   'W',   /* PQRSTUVW */
  62.    'X',   'Y',   'Z',   '[',   '\\',  ']',   '^',   '_',   /* XYZ[\]^_ */
  63.    '`',   'a',   '\b',  'c',   0177,  033,   014,   'g',   /* `abcdefg */
  64.    'h',   'i',   'j',   'k',   '\n',  'm',   '\n',  'o',   /* hijklmno */
  65.    'p',   'q',   '\r',  's',   '\t',  'u',   013,   'w',   /* pqrstuvw */
  66.    'x',   'y',   'z',   '{',   '|',   '}',   '~',   0177,  /* xyz{|}~ */
  67.    0200,  0201,  0202,  0203,  0204,  0205,  0206,  0207,
  68.    0210,  0211,  0212,  0213,  0214,  0215,  0216,  0217,
  69.    0220,  0221,  0222,  0223,  0224,  0225,  0226,  0227,
  70.    0230,  0231,  0232,  0233,  0234,  0235,  0236,  0237,
  71.    0240,  0241,  0242,  0243,  0244,  0245,  0246,  0247,
  72.    0250,  0251,  0252,  0253,  0254,  0255,  0256,  0257,
  73.    0260,  0261,  0262,  0263,  0264,  0265,  0266,  0267,
  74.    0270,  0271,  0272,  0273,  0274,  0275,  0276,  0277,
  75.    0300,  0301,  0302,  0303,  0304,  0305,  0306,  0307,
  76.    0310,  0311,  0312,  0313,  0314,  0315,  0316,  0317,
  77.    0320,  0321,  0322,  0323,  0324,  0325,  0326,  0327,
  78.    0330,  0331,  0332,  0333,  0334,  0335,  0336,  0337,
  79.    0340,  0341,  0342,  0343,  0344,  0345,  0346,  0347,
  80.    0350,  0351,  0352,  0353,  0354,  0355,  0356,  0357,
  81.    0360,  0361,  0362,  0363,  0364,  0365,  0366,  0367,
  82.    0370,  0371,  0372,  0373,  0374,  0375,  0376,  0377,
  83.   };
  84. #else                                   /* !EBCDIC */
  85. /*
  86.  *  This is the EBCDIC table for handling escapes.
  87.  */
  88. static unsigned char esctab[] = {
  89.    0x00,  0x01,  0x02,  0x03,  0x04,  0x05,  0x06,  0x07,
  90.    0x08,  0x09,  0x0a,  0x0b,  0x0c,  0x0d,  0x0e,  0x0f,
  91.    0x10,  0x11,  0x12,  0x13,  0x14,  0x15,  0x16,  0x17,
  92.    0x18,  0x19,  0x1a,  0x1b,  0x1c,  0x1d,  0x1e,  0x1f,
  93.    0x20,  0x21,  0x22,  0x23,  0x24,  0x25,  0x26,  0x27,
  94.    0x28,  0x29,  0x2a,  0x2b,  0x2c,  0x2d,  0x2e,  0x2f,
  95.    0x30,  0x31,  0x32,  0x33,  0x34,  0x35,  0x36,  0x37,
  96.    0x38,  0x39,  0x3a,  0x3b,  0x3c,  0x3d,  0x3e,  0x3f,
  97.    ' ',   0x41,  0x42,  0x43,  0x44,  0x45,  0x46,  0x47,
  98.    0x48,  0x49,  0x4a,  0x4b,  0x4c,  0x4d,  0x4e,  0x4f,
  99.    0x50,  0x51,  0x52,  0x53,  0x54,  0x55,  0x56,  0x57,
  100.    0x58,  0x59,  0x5a,  0x5b,  0x5c,  0x5d,  0x5e,  0x5f,
  101.    0x60,  0x61,  0x62,  0x63,  0x64,  0x65,  0x66,  0x67,
  102.    0x68,  0x69,  0x6a,  0x6b,  0x6c,  0x6d,  0x6e,  0x6f,
  103.    0x70,  0x71,  0x72,  0x73,  0x74,  0x75,  0x76,  0x77,
  104.    0x78,  0x79,  0x7a,  0x7b,  0x7c,  0x7d,  0x7e,  0x7f,
  105.    0x80,  'a',   0x16,  'c',   0x07,  0x27,  0x0c,  'g',
  106.    'h',   'i',   0x8a,  0x8b,  0x8c,  0x8d,  0x8e,  0x8f,
  107.  
  108. #if EBCDIC == 2
  109.    0x90,  'j',   'k',   0x15,  'm',   0x15,  'o',   'p',
  110. #else                    /* EBCDIC == 2 */
  111.    0x90,  'j',   'k',   0x25,  'm',   0x15,  'o',   'p',
  112. #endif                    /* EBCDIC == 2 */
  113.  
  114.    'q',   0x0d,  0x9a,  0x9b,  0x9c,  0x9d,  0x9e,  0x9f,
  115.    0xa0,  0xa1,  's',   0x05,  'u',   0x0b,  'w',   'x',
  116.    'y',   'z',   0xaa,  0xab,  0xac,  0xad,  0xae,  0xaf,
  117.    0xb0,  0xb1,  0xb2,  0xb3,  0xb4,  0xb5,  0xb6,  0xb7,
  118.    0xb8,  0xb9,  0xba,  0xbb,  0xbc,  0xbd,  0xbe,  0xbf,
  119.    0xc0,  'A',   0x16,  'C',   0x07,  0x27,  0x0c,  'G',
  120.    'H',   'I',   0xca,  0xcb,  0xcc,  0xcd,  0xce,  0xcf,
  121.  
  122. #if EBCDIC == 2
  123.    0xd0,  'J',   'K',   0x15,  'M',   0x15,  'O',   'P',
  124. #else                    /* EBCDIC == 2 */
  125.    0xd0,  'J',   'K',   0x25,  'M',   0x15,  'O',   'P',
  126. #endif                    /* EBCDIC == 2 */
  127.  
  128.    'Q',   0x0d,  0xda,  0xdb,  0xdc,  0xdd,  0xde,  0xdf,
  129.    0xe0,  0xe1,  'S',   0x05,  'U',   0x0b,  'W',   'X',
  130.    'Y',   'Z',   0xea,  0xeb,  0xec,  0xed,  0xee,  0xef,
  131.    0,   1,   2,   3,     4,     5,     6,     7,
  132.    8,   9,   0xfa,   0xfb,  0xfc,  0xfd,  0xfe,  0xff,
  133.    };
  134. #endif                    /* !EBCDIC */
  135.  
  136. struct node tok_loc =
  137.    {0, NULL, 0, 0};    /* "model" node containing location of current token */
  138.  
  139. struct toktab dottok =
  140.    {".", DOT, Beginner};    /* token struct for DOT token */
  141.  
  142. struct str_buf lex_sbuf;
  143.  
  144. /*
  145.  * yylex - find the next token in the input stream, and return its token
  146.  *  type and value to the parser.
  147.  *
  148.  * Variables of interest:
  149.  *
  150.  *  cc - character following last token.
  151.  *  nlflag - set if a newline was between the last token and the current token
  152.  *  lastend - set if the last token was an Ender.
  153.  *  lastval - when a semicolon is inserted and returned, lastval gets the
  154.  *   token value that would have been returned if the semicolon hadn't
  155.  *   been inserted.
  156.  */
  157.  
  158. static struct toktab *lasttok = NULL;
  159. static int lastend = 0;
  160. static int eofflag = 0;
  161. static int cc = '\n';
  162.  
  163. int yylex()
  164.    {
  165.    register struct toktab *t;
  166.    register int c;
  167.    int nlflag;
  168.    static nodeptr lastval;
  169.    static struct node semi_loc;
  170.  
  171.    if (lasttok != NULL) {
  172.       /*
  173.        * A semicolon was inserted and returned on the last call to yylex,
  174.        *  instead of going to the input, return lasttok and set the
  175.        *  appropriate variables.
  176.        */
  177.  
  178.       yylval = lastval;
  179.       tok_loc = *lastval;
  180.       t = lasttok;
  181.       goto ret;
  182.       }
  183.    nlflag = 0;
  184. loop:
  185.    c = cc;
  186.    /*
  187.     * Remember where a semicolon will go if we insert one.
  188.     */
  189.    semi_loc.n_file = tok_loc.n_file;
  190.    semi_loc.n_line = in_line;
  191.    if (cc == '\n')
  192.       --semi_loc.n_line;
  193.    semi_loc.n_col = incol;
  194.    /*
  195.     * Skip whitespace and comments and process #line directives.
  196.     */
  197.    while (c == Comment || isspace(c)) {
  198.       if (c == '\n') {
  199.          nlflag++;
  200.          c = NextChar;
  201.      if (c == Comment) {
  202.             /*
  203.          * Check for #line directive at start of line.
  204.              */
  205.             if (('l' == (c = NextChar)) &&
  206.                 ('i' == (c = NextChar)) &&
  207.                 ('n' == (c = NextChar)) &&
  208.                 ('e' == (c = NextChar))) {
  209.                c = setlineno();
  210.            while ((c == ' ') || (c == '\t'))
  211.           c = NextChar;
  212.                if (c != EOF && c != '\n')
  213.                   c = setfilenm(c);
  214.            }
  215.         while (c != EOF && c != '\n')
  216.                c = NextChar;
  217.         }
  218.          }
  219.       else {
  220.      if (c == Comment) {
  221.         while (c != EOF && c != '\n')
  222.                c = NextChar;
  223.         }
  224.          else {
  225.             c = NextChar;
  226.             }
  227.          }
  228.       }
  229.    /*
  230.     * A token is the next thing in the input.  Set token location to
  231.     *  the current line and column.
  232.     */
  233.    tok_loc.n_line = in_line;
  234.    tok_loc.n_col = incol;
  235.  
  236.    if (c == EOF) {
  237.       /*
  238.        * End of file has been reached.    Set eofflag, return T_Eof, and
  239.        *  set cc to EOF so that any subsequent scans also return T_Eof.
  240.        */
  241.       if (eofflag++) {
  242.      eofflag = 0;
  243.      cc = '\n';
  244.      yylval = NULL;
  245.      return 0;
  246.      }
  247.       cc = EOF;
  248.       t = T_Eof;
  249.       yylval = NULL;
  250.       goto ret;
  251.       }
  252.  
  253.    /*
  254.     * Look at current input character to determine what class of token
  255.     *  is next and take the appropriate action.  Note that the various
  256.     *  token gathering routines write a value into cc.
  257.     */
  258.    if (isalpha(c) || (c == '_')) {   /* gather ident or reserved word */
  259.       if ((t = getident(c, &cc)) == NULL)
  260.      goto loop;
  261.       }
  262.    else if (isdigit(c) || (c == '.')) {    /* gather numeric literal or "." */
  263.       if ((t = getnum(c, &cc)) == NULL)
  264.      goto loop;
  265.       }
  266.    else if (c == '"' || c == '\'') {    /* gather string or cset literal */
  267.       if ((t = getstring(c, &cc)) == NULL)
  268.      goto loop;
  269.       }
  270.    else {            /* gather longest legal operator */
  271.       if ((t = getopr(c, &cc)) == NULL)
  272.      goto loop;
  273.       yylval = OpNode(t->t_type);
  274.       }
  275.    if (nlflag && lastend && (t->t_flags & Beginner)) {
  276.       /*
  277.        * A newline was encountered between the current token and the last,
  278.        *  the last token was an Ender, and the current token is a Beginner.
  279.        *  Return a semicolon and save the current token in lastval.
  280.        */
  281.       lastval = yylval;
  282.       lasttok = t;
  283.       tok_loc = semi_loc;
  284.       yylval = OpNode(SEMICOL);
  285.       return SEMICOL;
  286.       }
  287. ret:
  288.    /*
  289.     * Clear lasttok, set lastend if the token being returned is an
  290.     *  Ender, and return the token.
  291.     */
  292.    lasttok = 0;
  293.    lastend = t->t_flags & Ender;
  294.    return (t->t_type);
  295.    }
  296.  
  297. #ifdef MultipleRuns
  298. /*
  299.  * yylexinit - initialize variables for multiple runs
  300.  */
  301. novalue yylexinit()
  302.    {
  303.    lasttok = NULL;
  304.    lastend = 0;
  305.    eofflag = 0;
  306.    cc = '\n';
  307.    }
  308.  
  309. #endif                    /* MultipleRuns */
  310. /*
  311.  * getident - gather an identifier beginning with ac.  The character
  312.  *  following identifier goes in cc.
  313.  */
  314.  
  315. static struct toktab *getident(ac, cc)
  316. int ac;
  317. int *cc;
  318.    {
  319.    register int c;
  320.    register struct toktab *t;
  321.  
  322.    c = ac;
  323.    /*
  324.     * Copy characters into string space until a non-alphanumeric character
  325.     *  is found.
  326.     */
  327.    do {
  328.       AppChar(lex_sbuf, c);
  329.       c = NextChar;
  330.       } while (isalnum(c) || (c == '_'));
  331.    *cc = c;
  332.    /*
  333.     * If the identifier is a reserved word, make a ResNode for it and return
  334.     *  the token value.  Otherwise, install it with putid, make an
  335.     *  IdNode for it, and return.
  336.     */
  337.    if ((t = findres()) != NULL) {
  338.       lex_sbuf.endimage = lex_sbuf.strtimage;
  339.       yylval = ResNode(t->t_type);
  340.       return t;
  341.       }
  342.    else {
  343.       yylval = IdNode(str_install(&lex_sbuf));
  344.       return (struct toktab *)T_Ident;
  345.       }
  346.    }
  347.  
  348. /*
  349.  * findres - if the string just copied into the string space by getident
  350.  *  is a reserved word, return a pointer to its entry in the token table.
  351.  *  Return NULL if the string isn't a reserved word.
  352.  */
  353.  
  354. static struct toktab *findres()
  355.    {
  356.    register struct toktab *t;
  357.    register char c;
  358.  
  359.    c = *lex_sbuf.strtimage;
  360.    if (!islower(c))
  361.       return NULL;
  362.    /*
  363.     * Point t at first reserved word that starts with c (if any).
  364.     */
  365.    if ((t = restab[c - 'a']) == NULL)
  366.       return NULL;
  367.    /*
  368.     * Search through reserved words, stopping when a match is found
  369.     *  or when the current reserved word doesn't start with c.
  370.     */
  371.    while (t->t_word[0] == c) {
  372.       if (bufcmp(t->t_word))
  373.      return t;
  374.       t++;
  375.       }
  376.    return NULL;
  377.    }
  378.  
  379. /*
  380.  * bufcmp - compare a null terminated string to what is in the string buffer.
  381.  */
  382. static int bufcmp(s)
  383. char *s;
  384.    {
  385.    register char *s1;
  386.    s1 = lex_sbuf.strtimage;
  387.    while (s != '\0' && s1 < lex_sbuf.endimage && *s == *s1) {
  388.       ++s;
  389.       ++s1;
  390.       }
  391.    if (*s == '\0' && s1 == lex_sbuf.endimage)
  392.       return 1;
  393.    else
  394.       return 0;
  395.    }
  396.  
  397. /*
  398.  * getnum - gather a numeric literal starting with ac and put the
  399.  *  character following the literal into *cc.
  400.  *
  401.  * getnum also handles the "." operator, which is distinguished from
  402.  *  a numeric literal by what follows it.
  403.  */
  404.  
  405. static struct toktab *getnum(ac, cc)
  406. int ac;
  407. int *cc;
  408.    {
  409.    register int c, r, state;
  410.    int realflag;
  411.  
  412.    c = ac;
  413.    if (c == '.') {
  414.       r = 0;
  415.       state = 7;
  416.       realflag = 1;
  417.       }
  418.    else {
  419.       r = tonum(c);
  420.       state = 0;
  421.       realflag = 0;
  422.       }
  423.    for (;;) {
  424.       AppChar(lex_sbuf, c);
  425.       c = NextChar;
  426.       switch (state) {
  427.      case 0:        /* integer part */
  428.         if (isdigit(c))        { r = r * 10 + tonum(c); continue; }
  429.         if (c == '.')           { state = 1; realflag++; continue; }
  430.         if (c == 'e' || c == 'E')  { state = 2; realflag++; continue; }
  431.         if (c == 'r' || c == 'R')  {
  432.            state = 5;
  433.            if (r < 2 || r > 36)
  434.           tfatal("invalid radix for integer literal", (char *)NULL);
  435.            continue;
  436.            }
  437.         break;
  438.      case 1:        /* fractional part */
  439.         if (isdigit(c))   continue;
  440.         if (c == 'e' || c == 'E')   { state = 2; continue; }
  441.         break;
  442.      case 2:        /* optional exponent sign */
  443.         if (c == '+' || c == '-') { state = 3; continue; }
  444.      case 3:        /* first digit after e, e+, or e- */
  445.         if (isdigit(c)) { state = 4; continue; }
  446.         tfatal("invalid real literal", (char *)NULL);
  447.         break;
  448.      case 4:        /* remaining digits after e */
  449.         if (isdigit(c))   continue;
  450.         break;
  451.      case 5:        /* first digit after r */
  452.         if ((isdigit(c) || isletter(c)) && tonum(c) < r)
  453.            { state = 6; continue; }
  454.         tfatal("invalid integer literal", (char *)NULL);
  455.         break;
  456.      case 6:        /* remaining digits after r */
  457.         if (isdigit(c) || isletter(c)) {
  458.            if (tonum(c) >= r) {    /* illegal digit for radix r */
  459.           tfatal("invalid digit in integer literal", (char *)NULL);
  460.           r = tonum('z');       /* prevent more messages */
  461.           }
  462.            continue;
  463.            }
  464.         break;
  465.          case 7:        /* token began with "." */
  466.             if (isdigit(c)) {
  467.                state = 1;        /* followed by digit is a real const */
  468.                continue;
  469.                }
  470.             *cc = c;            /* anything else is just a dot */
  471.             lex_sbuf.endimage--;    /* remove dot (undo AppChar) */
  472.             yylval = OpNode(DOT);
  473.             return &dottok;
  474.          }
  475.       break;
  476.       }
  477.    *cc = c;
  478.    if (realflag) {
  479.       yylval = RealNode(str_install(&lex_sbuf));
  480.       return T_Real;
  481.       }
  482.    yylval = IntNode(str_install(&lex_sbuf));
  483.    return T_Int;
  484.    }
  485.  
  486. /*
  487.  * getstring - gather a string literal starting with ac and place the
  488.  *  character following the literal in *cc.
  489.  */
  490.  
  491. static struct toktab *getstring(ac, cc)
  492. int ac;
  493. int *cc;
  494.    {
  495.    register int c, sc;
  496.    int sav_indx;
  497.    int len;
  498.  
  499.    sc = ac;
  500.    sav_indx = -1;
  501.    c = NextChar;
  502.    while (c != sc && c != '\n' && c != EOF) {
  503.       /*
  504.        * If a '_' is the last non-white space before a new-line,
  505.        *  we must remember where it is.
  506.        */
  507.       if (c == '_')
  508.          sav_indx = lex_sbuf.endimage - lex_sbuf.strtimage;
  509.       else if (!isspace(c))
  510.          sav_indx = -1;
  511.  
  512.       if (c == Escape) {
  513.          c = NextChar;
  514.          if (c == EOF)
  515.             break;
  516.  
  517. #ifdef VarTran
  518.          AppChar(lex_sbuf, Escape);
  519.          if (c == '^') {
  520.             c = NextChar;
  521.             if (c == EOF)
  522.                break;
  523.             AppChar(lex_sbuf, '^');
  524.             }
  525. #else                    /* VarTran */
  526.      if (isoctal(c))
  527.         c = octesc(c);
  528.      else if (c == 'x')
  529.         c = hexesc();
  530.      else if (c == '^')
  531.         c = ctlesc();
  532.      else
  533.         c = esctab[c];
  534. #endif                    /* VarTran */
  535.  
  536.      }
  537.       AppChar(lex_sbuf, c);
  538.       c = NextChar;
  539.  
  540.       /*
  541.        * If a '_' is the last non-white space before a new-line, the
  542.        *  string continues at the first non-white space on the next line
  543.        *  and everything from the '_' to the end of this line is ignored.
  544.        */
  545.       if (c == '\n' && sav_indx >= 0) {
  546.          lex_sbuf.endimage = lex_sbuf.strtimage + sav_indx;
  547.          while ((c = NextChar) != EOF && isspace(c))
  548.             ;
  549.          }
  550.       }
  551.    if (c == sc)
  552.       *cc = ' ';
  553.    else {
  554.       tfatal("unclosed quote", (char *)NULL);
  555.       *cc = c;
  556.       }
  557.    len = lex_sbuf.endimage - lex_sbuf.strtimage + 1; /* includes '\0' */
  558.    if (ac == '"') {     /* a string literal */
  559.       yylval = StrNode(str_install(&lex_sbuf), len);
  560.       return T_String;
  561.       }
  562.    else {        /* a cset literal */
  563.       yylval = CsetNode(str_install(&lex_sbuf), len);
  564.       return T_Cset;
  565.       }
  566.    }
  567.  
  568. #ifndef VarTran
  569.  
  570. /*
  571.  * ctlesc - translate a control escape -- backslash followed by
  572.  *  caret and one character.
  573.  */
  574.  
  575. static int ctlesc()
  576.    {
  577.    register int c;
  578.  
  579.    c = NextChar;
  580.    if (c == EOF)
  581.       return EOF;
  582.  
  583. #if !EBCDIC
  584.    return (c & 037);
  585. #else                    /* !EBCDIC */
  586.    return ToEBCDIC[FromEBCDIC[c] & 037];
  587.                         /* ctrl-x in EBCDIC is the EBCDIC equivalent */
  588.                         /* to ASCII ctrl-x                           */
  589. #endif                    /* !EBCDIC */
  590.  
  591.    }
  592.  
  593. /*
  594.  * octesc - translate an octal escape -- backslash followed by
  595.  *  one, two, or three octal digits.
  596.  */
  597.  
  598. static int octesc(ac)
  599. int ac;
  600.    {
  601.    register int c, nc, i;
  602.  
  603.    c = 0;
  604.    nc = ac;
  605.    i = 1;
  606.    do {
  607.       c = (c << 3) | (nc - '0');
  608.       nc = NextChar;
  609.       if (nc == EOF)
  610.      return EOF;
  611.       } while (isoctal(nc) && i++ < 3);
  612.    PushChar(nc);
  613.  
  614. #if EBCDIC != 2
  615.    return (c & 0377);
  616. #else                    /* EBCDIC != 2 */
  617.    return ToEBCDIC[c & 0377];
  618. #endif                    /* EBCDIC != 2 */
  619.    }
  620.  
  621. /*
  622.  * hexesc - translate a hexadecimal escape -- backslash-x
  623.  *  followed by one or two hexadecimal digits.
  624.  */
  625.  
  626. static int hexesc()
  627.    {
  628.    register int c, nc, i;
  629.  
  630.    c = 0;
  631.    i = 0;
  632.    while (i++ < 2) {
  633.       nc = NextChar;
  634.       if (nc == EOF)
  635.      return EOF;
  636.       if (nc >= 'a' && nc <= 'f')
  637.      nc -= 'a' - 10;
  638.       else if (nc >= 'A' && nc <= 'F')
  639.      nc -= 'A' - 10;
  640.       else if (isdigit(nc))
  641.      nc -= '0';
  642.       else {
  643.      PushChar(nc);
  644.      break;
  645.      }
  646.       c = (c << 4) | nc;
  647.       }
  648.  
  649. #if EBCDIC != 2
  650.    return c;
  651. #else                    /* EBCDIC != 2 */
  652.    return ToEBCDIC[c];
  653. #endif                    /* EBCDIC != 2 */
  654.  
  655.    }
  656.  
  657. #endif                    /* VarTran */
  658.  
  659. /*
  660.  * getopr - find the longest legal operator and return a pointer
  661.  *  to its entry in the token table.
  662.  */
  663.  
  664. static struct toktab *getopr(ac, cc)
  665. int ac;
  666. int *cc;
  667.    {
  668.    register struct optab *state;
  669.    register char c, i;
  670.  
  671.    state = state0;
  672.    c = ac;
  673.    for (;;) {
  674.       while ((i = state->o_input) && c != i)
  675.      state++;
  676.       switch (state->o_action) {
  677.      case A_Goto:
  678.         state = (struct optab *) state->o_val;
  679.         c = NextChar;
  680.         continue;
  681.      case A_Error:
  682.         tfatal("invalid character", (char *)NULL);
  683.         *cc = ' ';
  684.         return NULL;
  685.      case A_Return:
  686.         *cc = c;
  687.         return (struct toktab *)(state->o_val);
  688.      case A_Immret:
  689.         *cc = ' ';
  690.         return (struct toktab *)(state->o_val);
  691.      }
  692.       }
  693.    }
  694.  
  695. /*
  696.  * setlineno - set line number from #line comment, return following char.
  697.  */
  698.  
  699. static int setlineno()
  700.    {
  701.    register int c;
  702.  
  703.    while ((c = NextChar) == ' ' || c == '\t')
  704.       ;
  705.    if (c < '0' || c > '9') {
  706.       tfatal("no line number in #line directive", "");
  707.       while (c != EOF && c != '\n')
  708.      c = NextChar;
  709.       return c;
  710.       }
  711.    in_line = 0;
  712.    while (c >= '0' && c <= '9') {
  713.       in_line = in_line * 10 + (c - '0');
  714.       c = NextChar;
  715.       }
  716.    return c;
  717.    }
  718.  
  719. /*
  720.  * setfilenm -    set file name from #line comment, return following char.
  721.  */
  722.  
  723. static int setfilenm(c)
  724. register int c;
  725.    {
  726.    while (c == ' ' || c == '\t')
  727.       c = NextChar;
  728.    if (c != '"') {
  729.       tfatal("'\"' missing from file name in #line directive", "");
  730.       while (c != EOF && c != '\n')
  731.      c = NextChar;
  732.       return c;
  733.       }
  734.    while ((c = NextChar) != '"' && c != EOF && c != '\n')
  735.       AppChar(lex_sbuf, c);
  736.    if (c == '"') {
  737.       tok_loc.n_file = str_install(&lex_sbuf);
  738.       return NextChar;
  739.       }
  740.    else {
  741.       tfatal("'\"' missing from file name in #line directive", "");
  742.       return c;
  743.       }
  744.    }
  745.  
  746. /*
  747.  * nextchar - return the next character in the input.
  748.  */
  749.  
  750. static int nextchar()
  751.    {
  752.    register int c;
  753.  
  754. #if MACINTOSH
  755. #if MPW
  756.    {
  757.    static short cursorcount = CURSORINTERVAL;
  758.    if (--cursorcount == 0) {
  759.       RotateCursor(0);
  760.       cursorcount = CURSORINTERVAL;
  761.       }
  762.    }
  763. #endif                    /* MPW */
  764. #endif                    /* MACINTOSH */
  765.  
  766.    if (c = peekc) {
  767.       peekc = 0;
  768.       return c;
  769.       }
  770.    c = getc(srcfile);
  771.    switch (c) {
  772.       case EOF:
  773.      if (incol) {
  774.         c = '\n';
  775.         in_line++;
  776.         incol = 0;
  777.         peekc = EOF;
  778.         break;
  779.         }
  780.      else {
  781.         in_line = 0;
  782.         incol = 0;
  783.         break;
  784.         }
  785.       case '\n':
  786.      in_line++;
  787.      incol = 0;
  788.      break;
  789.       case '\t':
  790.      incol = (incol | 7) + 1;
  791.      break;
  792.       case '\b':
  793.      if (incol)
  794.         incol--;
  795.      break;
  796.       default:
  797.      incol++;
  798.       }
  799.    return c;
  800.    }
  801.